package sg.edu.nus.iss.billing.dao.customer;

import java.util.ArrayList;
import java.util.List;
import sg.edu.nus.iss.billing.common.DbUtil;
import sg.edu.nus.iss.billing.common.Util;

import sg.edu.nus.iss.billing.common.exception.BadDaoCallException;
import sg.edu.nus.iss.billing.common.exception.BadDbCallException;
import sg.edu.nus.iss.billing.common.exception.InvalidParamsException;
import sg.edu.nus.iss.billing.dao.customer.ICustomerDAO;
import sg.edu.nus.iss.billing.vo.customer.AddressVO;
import sg.edu.nus.iss.billing.vo.customer.CustomerVO;


public class CustomerDAO implements ICustomerDAO{
	private ArrayList<String> customerData = null;
	private ArrayList<String> addressData = null;
	public static final String CUSTOMER_FILE_PATH = "data//customer.txt";
	public static final String ADDRESS_FILE_PATH = "data//address.txt";
	public static String logImpl = "CLASSNAME : CustomerDAO : ";
	
	public CustomerDAO(){
		try {
			customerData = (ArrayList<String>) DbUtil.loadDb(CUSTOMER_FILE_PATH);
		} catch (BadDbCallException e) {
			customerData = new ArrayList<String>(); // assume empty db
			e.printStackTrace();
		}
		try {
			addressData = (ArrayList<String>) DbUtil.loadDb(ADDRESS_FILE_PATH);
		} catch (BadDbCallException e) {
			addressData = new ArrayList<String>(); // assume empty db
			e.printStackTrace();
		}
		
	}

	private void createCustomer(CustomerVO customer) throws BadDaoCallException{
		if (accountExist(customer.getAccount().getAccountNo())) {
			throw new BadDaoCallException ("Customer with same accountNo already exists!");
		}
		else
		{
			customerData.add(customer.serialised());
			addressData.add(customer.getAddress().serialised());
			try {
				DbUtil.saveDb(CUSTOMER_FILE_PATH, customerData);
			} catch (BadDbCallException e) {
				throw new BadDaoCallException (e.getMessage());
			}
			try {
				DbUtil.saveDb(ADDRESS_FILE_PATH, addressData);
			} catch (BadDbCallException e) {
				throw new BadDaoCallException (e.getMessage());
			}
		}
	}
		
	private boolean accountExist(String accountNo){
		for(int i=0;i<customerData.size();i++){
			CustomerVO customer = new CustomerVO();
			try {
				customer.setParameters(customerData.get(i));
				if (customer.getAccount().getAccountNo().equals(accountNo)) {
					return true;
				}
			} catch (InvalidParamsException e) {
				// skip invalid db entry
				e.printStackTrace();
			}
		}
		return false;
	}
	
	private void updateCustomer(CustomerVO customer) throws BadDaoCallException {
		for(int i=0;i<customerData.size();i++){
			CustomerVO c = new CustomerVO();
			try {
				c.setParameters(customerData.get(i));
				if (customer.getAccount().getAccountNo().equals(c.getAccount().getAccountNo())) {
					customerData.set(i, customer.serialised());
					customer.getAddress().setAddresseeNric(customer.getNric());
					updateAddress(customer.getAddress());
					try {
						DbUtil.saveDb(CUSTOMER_FILE_PATH, customerData);
					} catch (BadDbCallException e) {
						throw new BadDaoCallException (e.getMessage());
					}
				}
			} catch (InvalidParamsException e) {
				// skip invalid db entry
				e.printStackTrace();
			}
		}
	}
	
	private void updateAddress(AddressVO address) throws BadDaoCallException {
		for(int i=0;i<addressData.size();i++){
			AddressVO a = new AddressVO();
			try {
				a.setParameters(addressData.get(i));
				if (address.getAddresseeNric().equals(a.getAddresseeNric())) {
					addressData.set(i, address.serialised());
					try {
						DbUtil.saveDb(ADDRESS_FILE_PATH, addressData);
					} catch (BadDbCallException e) {
						throw new BadDaoCallException (e.getMessage());
					}
				}
			} catch (InvalidParamsException e) {
				// skip invalid db entry
				e.printStackTrace();
			}
		}
	}
	
	private AddressVO getAddress(String nric) {
		for(int i=0;i<addressData.size();i++){
			AddressVO a = new AddressVO();
			try {
				a.setParameters(addressData.get(i));
				if (a.getAddresseeNric().equals(nric)) {
					return a;
				}
			} catch (InvalidParamsException e) {
				// skip invalid db entry
				e.printStackTrace();
			}
		}
		// return empty address
		return new AddressVO();
	}
	
	private CustomerVO getCustomerByAccNo(String accountNo) {
		logImpl += " getCustomerByAccNo() accountNo : "+accountNo +" : ";
		CustomerVO customer = new CustomerVO();
		for(int i=0;i<customerData.size();i++){
			try {
				customer.setParameters(customerData.get(i));
				printLog(logImpl + "customer.getAccount() "+customer.getAccount().getAccountNo() );
				if (customer.getAccount().getAccountNo().equals(accountNo)) {
					customer.setAddress(getAddress(customer.getNric()));
					return customer;
				}
			} catch (InvalidParamsException e) {
				// skip corrupted db entry
				e.printStackTrace();
			}
		}
		return customer;
	}
	
	private CustomerVO getCustomer(String nric) {
		CustomerVO customer = null ;
		logImpl += " getCustomer() NRIC : "+nric +" : ";
		printLog(logImpl);
		for(int i=0;i<customerData.size();i++){
			try {
				customer =  new CustomerVO();
				customer.setParameters(customerData.get(i));
				printLog(logImpl + " : Iteration : customer.getNric()"+ customer.getNric() + " : "+customer.getNric().equals(nric) );
				if (customer.getNric().equals(nric)) {
					printLog(logImpl + " : Iteration : customer.setAddress(getAddress(customer.getNric())"+  getAddress(customer.getNric()));
					customer.setAddress(getAddress(customer.getNric()));
					printLog(logImpl + " : Iteration : customer.setAddress(getAddress(customer.getNric()) returning the CUSTOMERVO");
					return customer;
				}
			} catch (InvalidParamsException e) {
				// skip corrupted db entry
				e.printStackTrace();
			}
		}
		return null;
	}
	
	private List<CustomerVO> getCustomers() {
		ArrayList<CustomerVO> results = new ArrayList<CustomerVO>();
		for(int i=0;i<customerData.size();i++){
			try {
				CustomerVO customer = new CustomerVO();
				customer.setParameters(customerData.get(i));
				customer.setAddress(getAddress(customer.getNric()));
				results.add(customer);
			} catch (InvalidParamsException e) {
				// skip corrupted db entry
				e.printStackTrace();
			}
		}
		return results;
	}

	@Override
	public Object create(CustomerVO customer) {
		 try {
			createCustomer(customer);
			return "success";
		} catch (BadDaoCallException e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public int update(CustomerVO customer) {
		try {
			updateCustomer(customer);
		} catch (BadDaoCallException e) {
			e.printStackTrace();
			return 0;
		}
		return 1;
	}

	@Override
	public CustomerVO findCustomerByNric(String nric){
		return getCustomer(nric);
	}

	@Override
	public List<CustomerVO> findAllCustomers() {
		return getCustomers();
	}

	@Override
	public CustomerVO findCustomerByAcc(String accNo) {
		return getCustomerByAccNo(accNo);
	}
	
	public void test() {
		String nric = Util.generateRandomNric();
		String line1 = "Kent Ridge";
		String line2 = "123";
		String postalcode = "000001";
		String city = "Singapore";
		String state = "Singapore";
		String country = "Singapore";
		String accountNo = "ACCT"+Util.generateRandomNumer();
		String name = "Anderson";
		String contactNo = Util.generateRandomPhoneNumber();
		String interest = "I love coding";

		// create
		System.out.println("createCustomer");
		CustomerVO customer = new CustomerVO();
		customer.getAccount().setAccountNo(accountNo);
		customer.setNric(nric);
		customer.setCustomerNme(name);
		customer.setContactNo(contactNo);
		customer.setInterest(interest);
		AddressVO address = new AddressVO();
		address.setAddresseeNric(nric);
		address.setLine1(line1);
		address.setLine2(line2);
		address.setPostalCode(postalcode);
		address.setCity(city);
		address.setState(state);
		address.setCountry(country);
		customer.setAddress(address);
		try {
			createCustomer(customer);
		} catch (BadDaoCallException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		DbUtil.printDb(customerData);
		DbUtil.printDb(addressData);
		// update 
		System.out.println("update Customer");
		name = "AndersonIceCream";
		customer.setCustomerNme(name);
		try {
			updateCustomer(customer);
		} catch (BadDaoCallException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		DbUtil.printDb(customerData);
		DbUtil.printDb(addressData);
		// find
		System.out.println("find customer");
		CustomerVO cus = getCustomer(nric);
		System.out.println(cus.serialised());
		// find by account
		System.out.print("find customer by account");
		CustomerVO cus2 = getCustomerByAccNo(accountNo);
		System.out.println(cus2.serialised());
		
	}
	
	private void printLog(String str){
		System.out.println(str);
	}
		

}
